package cn.haoma.base.img;

import android.annotation.SuppressLint;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

@SuppressLint("HandlerLeak")
/**
 * @author Hunter
 */ public class ImgLoader {
    private String TAG = ImgLoader.class.getName();
    /**
     * 解码Task对象缓存池
     */
    private LinkedList<DecodeTask> decodeTaskObjCachePool = new LinkedList<DecodeTask>();
    /**
     * 返回1解码成功，返回2下载成功，返回3解码失败，返回4下载失败
     */
    private static Handler handler = new Handler() {
        public void handleMessage(Message msg) {
            DecodeTask task = (DecodeTask) msg.obj;
            task.postResult();
        }

        ;
    };
    /**
     * 单线程处理解码任务
     */
    private ExecutorService decodeThreadPool = Executors.newSingleThreadExecutor();
    /**
     * 下载Task对象缓存池
     */
    private LinkedList<DownloadTask> downloadTaskObjCachePool = new LinkedList<DownloadTask>();
    /**
     * 下载个别URL对应的网址下载速度慢阻塞任务。
     * 如果图片来自一个服务器，单线程下载即可，（制约因素在服务器网速）
     * 如果图片来自不同的服务器，一般情况开多个线程下载效率高一些。
     * 如果自己的网速很差劲，开一个线程效率会高一些。
     */
    //	private ExecutorService downloadThreadPool = Executors.newSingleThreadExecutor();
    private ExecutorService downloadThreadPool = Executors.newFixedThreadPool(4);
    /**
     * 保存所有的Img对象，方便对象的回收，数量级可能上百上千
     */
    private HashSet<Img> imgSet = new LinkedHashSet<Img>();
    private boolean isShutDown;
    private long startTimeLine;
    /**
     * 任务集合，主要用于防止重发添加任务
     */
    private HashSet<Img> taskImgSet = new HashSet<Img>();
    /**
     * 记录所有的ImageView，在回收Bitmap之前先设置其Bitmap资源为null
     */
    private HashSet<View> viewSet = new HashSet<View>();

    public ImgLoader() {
        ImgUtil.registMemoryAlarm(new ImgUtil.MemoryListener() {
            @Override
            public void onLowMemory() {
                releaseSomeMemory();
            }

            @Override
            public void onOutOfMemory() {
                releaseSomeMemory();
            }
        });
    }

    /**
     * 释放一部分内存
     */
    public void releaseSomeMemory() {
        Log.e(ImgLoader.class.getName(), "OutOfMemory: 开始释放内存");
        try {
            int num = 0;
            for (Img img : imgSet) {
                if (img.isBitmapDecoded() && !isImgVisible(img)) {
                    Bitmap bitmap = img.getBitmap();
                    Log.e(ImgLoader.class.getName(), "释放内存" + (bitmap.getHeight() * bitmap.getWidth() * 4 / 1024) + "/kb");
                    img.recycle();
                    num++;
                }
                if (num > 20) {
                    break;
                }
            }
            System.gc();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Error e) {
            e.printStackTrace();
        }
    }

    /**
     * Img对象绑定的ImageView有一个可见即认为是可见
     */
    final private boolean isImgVisible(Img img) {
        if (isShutDown) {
            return false;
        }
        for (View view : img.getBindedViews()) {
            if (view.getTag(Integer.MAX_VALUE) == img) {
                return true;
            }
        }
        return false;
    }

    /**
     * 一个Img对象可以绑定一个ImageView对象 ，一个ImageView对象只能绑定一个Img对象
     *
     * @param img
     * @param view
     */
    public void bind(Img img, View view) {
        bindImgToView(img, view);
        if (img.isBitmapDecoded()) {
            img.getImgListener().onBitmapDecoded(img.getBitmap(), view, false);
        } else {
            img.getImgListener().onImgBindWithNoBitmapCache(view);
            viewSet.add(view);
            if (!taskImgSet.contains(img)) {
                taskImgSet.add(img);
                imgSet.add(img);
                if (img.getUrl() == null || img.fileExists()) {
                    DecodeTask task = obtainDecodeTask(img);
                    decodeThreadPool.execute(task);
                } else {
                    DownloadTask task = obtainDownloadTask(img);
                    downloadThreadPool.execute(task);
                }
            }
        }
    }

    private void bindImgToView(Img img, View view) {
        Img oldImg = (Img) view.getTag(Integer.MAX_VALUE);
        if (img == oldImg) {
            return;
        }
        if (null != oldImg) {//view绑定了新的Img，以前的Img和此view解绑
            oldImg.unbindView(view);
        }
        img.bindView(view);
        view.setTag(Integer.MAX_VALUE, img);
    }

    private DecodeTask obtainDecodeTask(Img img) {
        DecodeTask task = null;
        try {
            task = decodeTaskObjCachePool.poll();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (null == task) {
            task = new DecodeTask(img);
        } else {
            task.img = img;
        }
        return task;
    }

    /**
     * 用Img对象创建一个下载任务
     *
     * @param img
     * @return
     */
    private DownloadTask obtainDownloadTask(Img img) {
        DownloadTask task = null;
        try {
            //从对象缓存池获取一个对象
            task = downloadTaskObjCachePool.poll();
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (null == task) {
            task = new DownloadTask(img);
        } else {
            task.img = img;
        }
        return task;
    }

    public void releaseImgWithListener(Object imgListener) {
        try {
            int num = 0;
            for (Img img : imgSet) {
                if (imgListener == img.getImgListener()) {
                    img.recycle();
                    imgSet.remove(img);
                    viewSet.removeAll(img.getBindedViews());
                }
            }
            System.gc();
        } catch (Exception e) {
            e.printStackTrace();
        } catch (Error e) {
            e.printStackTrace();
        }
    }

    /**
     * 关闭线程池，清理Bitmap对象，onDestory()时使用
     */
    public void shutdown() {
        Log.i(TAG, "Shut down the ThreadPool and Recycle Bitmaps");
        isShutDown = true;
        downloadThreadPool.shutdownNow();
        decodeThreadPool.shutdownNow();
        for (View v : viewSet) {
            v.setVisibility(View.INVISIBLE);
        }
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                for (Img img : imgSet) {
                    img.recycle();
                    img = null;
                }
            }
        }, 1000);

    }

    /**
     * ListView 滑动过程中可调用此方法给主线程腾出资源
     *
     * @param time
     */
    public void waitMainThread(long time) {
        startTimeLine = System.currentTimeMillis() + time;
    }

    private class DecodeTask implements Runnable {
        public Img img;

        public DecodeTask(Img image) {
            this.img = image;
        }

        public void postResult() {
            for (View v : img.getBindedViews()) {
                if (v.getTag(Integer.MAX_VALUE) == img) {
                    img.getImgListener().onBitmapDecoded(img.getBitmap(), v, true);
                }
            }
            decodeTaskObjCachePool.add(this);
        }

        @Override
        public void run() {

            try {
                while (startTimeLine > System.currentTimeMillis()) {
                    Thread.yield();
                }
                if (isImgVisible(img)) {
                    if (img.decodeBitmap()) {
                        if (isImgVisible(img)) {
                            sendDecodedFinishMessage();
                        }
                    }
                }
            } catch (Exception e) {
                img.deleteCacheFile();
                if (img.getUrl() != null) {
                    img.deleteFile();
                }
                Log.e(TAG, "Pic Decode Failure ！ FilePath: " + img.getImagePath());
                e.printStackTrace();
            } catch (Error e) {
                e.printStackTrace();
            }

            taskImgSet.remove(this.img);
        }

        private void sendDecodedFinishMessage() {
            Message message = Message.obtain();
            message.obj = this;
            handler.sendMessage(message);
        }


    }

    private class DownloadTask implements Runnable {
        public int badUrlIndicator;
        public Img img;

        public DownloadTask(Img image) {
            this.img = image;
        }        @Override
        public void run() {
            try {
                Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
                while (startTimeLine > System.currentTimeMillis()) {
                    Thread.yield();
                }
                if (isImgVisible(img)) {// 图片可见
                    boolean result = img.download();// 耗时
                    if (result) {
                        if (!isShutDown) {
                            DecodeTask task = obtainDecodeTask(img);
                            decodeThreadPool.execute(task);
                        }

                    } else {
                        Log.e(TAG, "重新提交下载任务:RUL=" + img.getUrl());
                        if (badUrlIndicator < 3) {
                            badUrlIndicator++;
                            downloadThreadPool.execute(this);
                        } else {
                            Log.e(TAG, "不再重新提交下载任务:RUL=" + img.getUrl());
                            badUrlIndicator = 0;
                            taskImgSet.remove(this);
                            downloadTaskObjCachePool.addLast(this);
                        }
                    }
                } else {
                    taskImgSet.remove(this.img);
                }
                downloadTaskObjCachePool.addLast(this);
            } catch (Exception e) {
                e.printStackTrace();
            } catch (Error e) {
                e.printStackTrace();
            }
        }



    }
}
